#include"socket.h"

#include"spi_tx_rx.h"
#include"w5500.h"
#include "w5500_set.h"

uint8_t socket_w5500(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag,int fd)
{
   uint8_t ret;
   if (
        ((protocol&0x0F) == Sn_MR_TCP)    ||
        ((protocol&0x0F) == Sn_MR_UDP)    ||
        ((protocol&0x0F) == Sn_MR_IPRAW)  ||
        ((protocol&0x0F) == Sn_MR_MACRAW) ||
        ((protocol&0x0F) == Sn_MR_PPPOE)
      )
   {
      close_w5500(s,fd);
      IINCHIP_WRITE(Sn_MR(s) ,protocol | flag,fd);
      if (port != 0) {
         IINCHIP_WRITE( Sn_PORT0(s) ,(uint8_t)((port & 0xff00) >> 8),fd);
         // printf("Sn_PORT0=%d   data= %d   %d\r\n",Sn_PORT0(s),(uint8_t)((port & 0xff00) >> 8),__LINE__);
         IINCHIP_WRITE( Sn_PORT1(s) ,(uint8_t)(port & 0x00ff),fd);
         //  printf("%d\r\n",__LINE__);
      } else {
         local_port++; // if don't set the source port, set local_port number.
         IINCHIP_WRITE(Sn_PORT0(s) ,(uint8_t)((local_port & 0xff00) >> 8),fd);
         //  printf("%d\r\n",__LINE__);
         IINCHIP_WRITE(Sn_PORT1(s) ,(uint8_t)(local_port & 0x00ff),fd);
         //  printf("%d\r\n",__LINE__);
      }
      IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_OPEN,fd); // run sockinit Sn_CR

      /* wait to process the command... */
      while( IINCHIP_READ(Sn_CR(s),fd))
         ;
      /* ------- */
      ret = 1;
   }
   else
   {
      ret = 0;
   }
   printf("local_port = %d\r\n",local_port);
   return ret;
}

void close_w5500(SOCKET s,int fd)
{
   IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_CLOSE,fd);
   /* wait to process the command... */
   while( IINCHIP_READ(Sn_CR(s),fd) )
       ;/* ------- */
   
	IINCHIP_WRITE( Sn_IR(s) , 0xFF,fd);	 /* all clear */
}

uint8_t listen_w5500(SOCKET s,int fd)
{
   uint8_t ret;
   if (IINCHIP_READ( Sn_SR(s),fd) == SOCK_INIT)
   {
      printf("listening\r\n");
      IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_LISTEN,fd);
      /* wait to process the command... */
      while( IINCHIP_READ(Sn_CR(s),fd) )
      {
         printf(".");
         sleep(1);
      }
         ;
      /* ------- */
      ret = 1;
   }
   else
   {
      ret = 0;
   }
   return ret;
}


uint8_t connect_w5500(SOCKET s, uint8_t * addr, uint16_t port,int fd)
{
    uint8_t ret;
    if
        (
            ((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) ||
            ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
            (port == 0x00)
        )
    {
      ret = 0;
    }
    else
    {
        ret = 1;
        // set destination IP
        IINCHIP_WRITE( Sn_DIPR0(s), addr[0],fd);
        IINCHIP_WRITE( Sn_DIPR1(s), addr[1],fd);
        IINCHIP_WRITE( Sn_DIPR2(s), addr[2],fd);
        IINCHIP_WRITE( Sn_DIPR3(s), addr[3],fd);
        IINCHIP_WRITE( Sn_DPORT0(s), (uint8_t)((port & 0xff00) >> 8),fd);
        IINCHIP_WRITE( Sn_DPORT1(s), (uint8_t)(port & 0x00ff),fd);
        IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_CONNECT,fd);
        /* wait for completion */
        while ( IINCHIP_READ(Sn_CR(s),fd) ) ;

        while ( IINCHIP_READ(Sn_SR(s),fd) != SOCK_SYNSENT )
        {
            if(IINCHIP_READ(Sn_SR(s),fd) == SOCK_ESTABLISHED)
            {
                break;
            }
            if (getSn_IR(s,fd) & Sn_IR_TIMEOUT)
            {
                IINCHIP_WRITE(Sn_IR(s), (Sn_IR_TIMEOUT),fd);  // clear TIMEOUT Interrupt
                ret = 0;
                break;
            }
        }
    }

   return ret;
}

void disconnect_w5500(SOCKET s,int fd)
{
   IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_DISCON,fd);
   /* wait to process the command... */
   while( IINCHIP_READ(Sn_CR(s),fd) )
      ;
   /* ------- */
}

uint16_t send_w5500(SOCKET s, const uint8_t * buf, uint16_t len,int fd)
{
  uint8_t status=0;
  uint16_t ret=0;
  uint16_t freesize=0;

  if (len > getIINCHIP_TxMAX(s)) ret = getIINCHIP_TxMAX(s); // check size not to exceed MAX size.
  else ret = len;

  // if freebuf is available, start.
  do
  {
    freesize = getSn_TX_FSR(s,fd);
    status = IINCHIP_READ(Sn_SR(s),fd);
    if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT))
    {
      ret = 0;
      break;
    }
  } while (freesize < ret);
  
  // copy data
  send_data_processing(s, (uint8_t *)buf, ret,fd);
  IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_SEND,fd);

  /* wait to process the command... */
  while( IINCHIP_READ(Sn_CR(s),fd) );

  while ( (IINCHIP_READ(Sn_IR(s),fd) & Sn_IR_SEND_OK) != Sn_IR_SEND_OK )
  {
    status = IINCHIP_READ(Sn_SR(s),fd);
    if ((status != SOCK_ESTABLISHED) && (status != SOCK_CLOSE_WAIT) )
    {
      printf("SEND_OK Problem!!\r\n");
      close_w5500(s,fd);
      return 0;
    }
  }
  IINCHIP_WRITE( Sn_IR(s) , Sn_IR_SEND_OK,fd);

#ifdef __DEF_IINCHIP_INT__
   putISR(s, getISR(s) & (~Sn_IR_SEND_OK));
#else
   IINCHIP_WRITE( Sn_IR(s) , Sn_IR_SEND_OK,fd);
#endif

   return ret;
}

uint16_t recv_w5500(SOCKET s, uint8_t * buf, uint16_t len,int fd)
{
   uint16_t ret=0;
   if ( len > 0 )
   {
      recv_data_processing(s, buf, len,fd);
      IINCHIP_WRITE( Sn_CR(s) ,Sn_CR_RECV,fd);
      /* wait to process the command... */
      while( IINCHIP_READ(Sn_CR(s),fd));
      /* ------- */
      ret = len;
   }
   return ret;
}
